home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / lib / c / net / res_query.c < prev    next >
C/C++ Source or Header  |  1988-07-29  |  7KB  |  252 lines

  1. /*
  2.  * Copyright (c) 1988 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that this notice is preserved and that due credit is given
  7.  * to the University of California at Berkeley. The name of the University
  8.  * may not be used to endorse or promote products derived from this
  9.  * software without specific prior written permission. This software
  10.  * is provided ``as is'' without express or implied warranty.
  11.  */
  12.  
  13. #if defined(LIBC_SCCS) && !defined(lint)
  14. static char sccsid[] = "@(#)res_query.c    5.4 (Berkeley) 4/21/88";
  15. #endif /* LIBC_SCCS and not lint */
  16.  
  17. #include <sys/param.h>
  18. #include <sys/socket.h>
  19. #include <netinet/in.h>
  20. #include <ctype.h>
  21. #include <netdb.h>
  22. #include <stdio.h>
  23. #include <errno.h>
  24. #include <strings.h>
  25. #include <arpa/inet.h>
  26. #include <arpa/nameser.h>
  27. #include <resolv.h>
  28.  
  29. #if PACKETSZ > 1024
  30. #define MAXPACKET    PACKETSZ
  31. #else
  32. #define MAXPACKET    1024
  33. #endif
  34.  
  35. extern int errno;
  36. int h_errno;
  37.  
  38. /*
  39.  * Formulate a normal query, send, and await answer.
  40.  * Returned answer is placed in supplied buffer "answer".
  41.  * Perform preliminary check of answer, returning success only
  42.  * if no error is indicated and the answer count is nonzero.
  43.  * Return the size of the response on success, -1 on error.
  44.  * Error number is left in h_errno.
  45.  * Caller must parse answer and determine whether it answers the question.
  46.  */
  47. res_query(name, class, type, answer, anslen)
  48.     char *name;        /* domain name */
  49.     int class, type;    /* class and type of query */
  50.     u_char *answer;        /* buffer to put answer */
  51.     int anslen;        /* size of answer buffer */
  52. {
  53.     char buf[MAXPACKET];
  54.     HEADER *hp;
  55.     int n;
  56.  
  57.     if ((_res.options & RES_INIT) == 0 && res_init() == -1)
  58.         return (-1);
  59. #ifdef DEBUG
  60.     if (_res.options & RES_DEBUG)
  61.         printf("res_query(%s, %d, %d)\n", name, class, type);
  62. #endif
  63.     n = res_mkquery(QUERY, name, class, type, (char *)NULL, 0,
  64.         (struct rrec *) NULL, buf, sizeof(buf));
  65.  
  66.     if (n <= 0) {
  67. #ifdef DEBUG
  68.         if (_res.options & RES_DEBUG)
  69.             printf("res_query: mkquery failed\n");
  70. #endif
  71.         h_errno = NO_RECOVERY;
  72.         return (n);
  73.     }
  74.     n = res_send(buf, n, (char *) answer, anslen);
  75.     if (n < 0) {
  76. #ifdef DEBUG
  77.         if (_res.options & RES_DEBUG)
  78.             printf("res_query: send error\n");
  79. #endif
  80.         h_errno = TRY_AGAIN;
  81.         return(n);
  82.     }
  83.  
  84.     hp = (HEADER *) answer;
  85.     if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
  86. #ifdef DEBUG
  87.         if (_res.options & RES_DEBUG)
  88.             printf("rcode = %d, ancount=%d\n", hp->rcode,
  89.                 ntohs(hp->ancount));
  90. #endif
  91.         switch (hp->rcode) {
  92.             case NXDOMAIN:
  93.                 h_errno = HOST_NOT_FOUND;
  94.                 break;
  95.             case SERVFAIL:
  96.                 h_errno = TRY_AGAIN;
  97.                 break;
  98.             case NOERROR:
  99.                 h_errno = NO_DATA;
  100.                 break;
  101.             case FORMERR:
  102.             case NOTIMP:
  103.             case REFUSED:
  104.             default:
  105.                 h_errno = NO_RECOVERY;
  106.                 break;
  107.         }
  108.         return (-1);
  109.     }
  110.     return(n);
  111. }
  112.  
  113. /*
  114.  * Formulate a normal query, send, and retrieve answer in supplied buffer.
  115.  * Return the size of the response on success, -1 on error.
  116.  * If enabled, implement search rules until answer or unrecoverable failure
  117.  * is detected.  Error number is left in h_errno.
  118.  * Only useful for queries in the same name hierarchy as the local host
  119.  * (not, for example, for host address-to-name lookups in domain in-addr.arpa).
  120.  */
  121. res_search(name, class, type, answer, anslen)
  122.     char *name;        /* domain name */
  123.     int class, type;    /* class and type of query */
  124.     u_char *answer;        /* buffer to put answer */
  125.     int anslen;        /* size of answer */
  126. {
  127.     register char *cp, **domain;
  128.     int n, ret, got_nodata = 0;
  129.     char *hostalias();
  130.  
  131.     if ((_res.options & RES_INIT) == 0 && res_init() == -1)
  132.         return (-1);
  133.  
  134.     errno = 0;
  135.     h_errno = HOST_NOT_FOUND;        /* default, if we never query */
  136.     for (cp = name, n = 0; *cp; cp++)
  137.         if (*cp == '.')
  138.             n++;
  139.     if (n == 0 && (cp = hostalias(name)))
  140.         return (res_query(cp, class, type, answer, anslen));
  141.  
  142.     if ((n == 0 || *--cp != '.') && (_res.options & RES_DEFNAMES))
  143.         for (domain = _res.dnsrch; *domain; domain++) {
  144.         ret = res_querydomain(name, *domain, class, type,
  145.             answer, anslen);
  146.         if (ret > 0)
  147.             return (ret);
  148.         /*
  149.          * If no server present, give up.
  150.          * If name isn't found in this domain,
  151.          * keep trying higher domains in the search list
  152.          * (if that's enabled).
  153.          * On a NO_DATA error, keep trying, otherwise
  154.          * a wildcard entry of another type could keep us
  155.          * from finding this entry higher in the domain.
  156.          * If we get some other error (non-authoritative negative
  157.          * answer or server failure), then stop searching up,
  158.          * but try the input name below in case it's fully-qualified.
  159.          */
  160.         if (errno == ECONNREFUSED) {
  161.             h_errno = TRY_AGAIN;
  162.             return (-1);
  163.         }
  164.         if (h_errno == NO_DATA)
  165.             got_nodata++;
  166.         if ((h_errno != HOST_NOT_FOUND && h_errno != NO_DATA) ||
  167.             (_res.options & RES_DNSRCH) == 0)
  168.             break;
  169.     }
  170.     /*
  171.      * If the search/default failed, try the name as fully-qualified,
  172.      * but only if it contained at least one dot (even trailing).
  173.      */
  174.     if (n)
  175.         return (res_querydomain(name, (char *)NULL, class, type,
  176.             answer, anslen));
  177.     if (got_nodata)
  178.         h_errno = NO_DATA;
  179.     return (-1);
  180. }
  181.  
  182. /*
  183.  * Perform a call on res_query on the concatenation of name and domain,
  184.  * removing a trailing dot from name if domain is NULL.
  185.  */
  186. res_querydomain(name, domain, class, type, answer, anslen)
  187.     char *name, *domain;
  188.     int class, type;    /* class and type of query */
  189.     u_char *answer;        /* buffer to put answer */
  190.     int anslen;        /* size of answer */
  191. {
  192.     char nbuf[2*MAXDNAME+2];
  193.     char *longname = nbuf;
  194.     int n;
  195.  
  196. #ifdef DEBUG
  197.     if (_res.options & RES_DEBUG)
  198.         printf("res_querydomain(%s, %s, %d, %d)\n",
  199.             name, domain, class, type);
  200. #endif
  201.     if (domain == NULL) {
  202.         /*
  203.          * Check for trailing '.';
  204.          * copy without '.' if present.
  205.          */
  206.         n = strlen(name) - 1;
  207.         if (name[n] == '.' && n < sizeof(nbuf) - 1) {
  208.             bcopy(name, nbuf, n);
  209.             nbuf[n] = '\0';
  210.         } else
  211.             longname = name;
  212.     } else
  213.         (void)sprintf(nbuf, "%.*s.%.*s",
  214.             MAXDNAME, name, MAXDNAME, domain);
  215.  
  216.     return (res_query(longname, class, type, answer, anslen));
  217. }
  218.  
  219. char *
  220. hostalias(name)
  221.     register char *name;
  222. {
  223.     register char *C1, *C2;
  224.     FILE *fp;
  225.     char *file, *getenv(), *strcpy(), *strncpy();
  226.     char buf[BUFSIZ];
  227.     static char abuf[MAXDNAME];
  228.  
  229.     file = getenv("HOSTALIASES");
  230.     if (file == NULL || (fp = fopen(file, "r")) == NULL)
  231.         return (NULL);
  232.     buf[sizeof(buf) - 1] = '\0';
  233.     while (fgets(buf, sizeof(buf), fp)) {
  234.         for (C1 = buf; *C1 && !isspace(*C1); ++C1);
  235.         if (!*C1)
  236.             break;
  237.         *C1 = '\0';
  238.         if (!strcasecmp(buf, name)) {
  239.             while (isspace(*++C1));
  240.             if (!*C1)
  241.                 break;
  242.             for (C2 = C1 + 1; *C2 && !isspace(*C2); ++C2);
  243.             abuf[sizeof(abuf) - 1] = *C2 = '\0';
  244.             (void)strncpy(abuf, C1, sizeof(abuf) - 1);
  245.             fclose(fp);
  246.             return (abuf);
  247.         }
  248.     }
  249.     fclose(fp);
  250.     return (NULL);
  251. }
  252.